CH04 - Over Fitting and model tunning

Modelos atuais conseguem representar quaisquer padrões nos dados, infelizmente eles podem over fitar (representar padrões que não são reproduziveis no decorrer do tempo), para avaliar modelos precisamos de uma metodologia sitemática. Nesse capítulo serão descritas técnicas para garantir um mesmo resultado para modelos no decorrer do tempo e evitar overfit. Nesse capítulo assume-se que os dados são representativos da população e que há uma qualidade mínima na proveniência de dados das amostras.

Com essas condições, nosso objetivo é tunar o modelo sem overfita-lo. Para tal dividimos o conjunto de dados em treino/teste, abordagens mais modernas dividem em vários conjuntos de treino/teste para atingir um resultado melhor do modelo.

The problem of over-fitting

Técnicas que aprendem muito bem a estrutura dos dados tão bem que ao ser aplicado nos dados onde o modelo foi construído prediz corretamente \(100%\) da amostra. Além de aprender os padrões gerais de comportamento dos dados o modelo aprendeu o ruído de cada dado, isso significa que o modelo overfitou

Conjunto de treino com dois preditores

Conjunto de treino com dois preditores

A figura acima, será usada para ilustrar o conceito de over-fitting, contém \(208\) exemplos e é um problema de classificação binária, com duas variáveis preditoras. Há um leve desbalanceamento nas classes \(111\) classe 1 e \(97\) classe 2 além disso existe uma sobreposição de classes, um problema tipicamente encontrado. Um modelo que use esses dados tem tipicamente um objetivo: predizer novos dados, o modelo pode ser representado como um fronteira(s) de decisão(ões).

Fronteiras de decisão

Fronteiras de decisão

A figura acima mostra dois possíveis modelos para solucionar esse problema, o primeiro separa cada conjunto de dados da classe 1 e alega que o restante seria da classe 2. Podemos perceber que esse padrão não é muito generalizável. O modelo da direita, apresenta uma fronteira de decisão menos rígida que não classifica corretamente todos os pontos, mas tem maior probabilidade de generalizar.

Nesse exmplo simplista, com apenas duas variáveis, é simples observar o over-fitting do modelo da esquerda. No mundo real modelos tem muitas outras variáveis tornando essa abordagem visual impraticável. Necessitamos de uma ferramenta para averiguar o grau de over-fitting.

Model tunning

Muitos modelos tem parâmetros impossíveis de serem estimados usando os dados, como o KNN, devemos informar o número de vizinhos. Ao escolher muitos vizinhos podemos não conseguir aprender o suficiente dos dados, ao escolher poucos podemos facilmente over-fittar. Esse tipo de parâmetro é conhecido por: parâmetro de tunning muitos modelos apresentam pelo menos um desses parâmetros. Fronteiras de decisão

A escolha desses parâmetros aumentam ou reduzem o grau de especialização do modelo, podendo, causar over-fitting. POr exemplo o parâmetro custo do SVM C que informa o peso do erro de classificação do modelo, ao setar um valor grande para esse parâmetro, temos um modelo altamente over-fittado enquanto que um valor baixo indica um modelo com resultados baixos. No painel da direita da figura fronteiras de decisão foi escolhido um valor alto, no painel da esquerda foi escolhido um valor usando validação cruzada.

Uma abordagem para escolha de parâmetros é selecionar um subconjunto deles, treinar diversos modelos e observar o melhor entre eles. Esse processo pode ser visualizado na figura abaixo: Fronteiras de decisão

Após selecionar um conjuntto de parâmetros aceitáveis para treinarmos o modelo devemos encontrar uma métrica (confiável) para avaliarmos sua performance. Nesse ponto aplicamos uma estratégia de força bruta nos dados e nos parâmetros para encontrarmos o melhor modelo e parâmetro. Outras abordagens para encontrar os parâmetros ótimo são usar algoritmos genéticos ou métodos de de busca baseados em simplex.

O maior problema é encontrar uma estimativa confiável para esses modelos e definir qual o melhor dentre eles, como vimos anteiormente taxa de erro pode nos levar a uma falsa sensação de segurança. Uma abordagem usada é testar o modelo para uma amostra não usada para treinar o mesmo, seu tamanho deve ser considerável.

Uma outra abordagem é usar um conjunto apenas de teste reamostrando o conjunto de treinamento, para realizar isso existem algumas técnicas estatísticas que serão abordadas adiante.

Divisão de dados

O coração do processo para encontrar os parâmetros ótimo é a divisão do conjunto de dados, a construção do modelo segue os seguintes passos:

  1. Pré-processamento dos preditores
  2. Estimação dos parâmetros
  3. Seleção de preditores
  4. Avaliação da performance
  5. Ajuste fino das regras de classificação (tipicamente usando curvas ROC)

Dado que há um conjunto fixo de pontos de amostra, o modelador deve decidir como distribui-los nessas etapas. A principal escolha são os pontos que serão usados para avaliar o modelo, idealmente não devem ser os mesmos usados para treinar/ajustar finamente o modelo, dessa forma, eles representam valores não viesados. Quando há um conjunto de dados grande e expressivo podemos separar os conjuntos em validação e teste sem problemas, usando um para treinar e outro para validar.

Quando não há um conjunto de dados grande o suficiente não fazemos um conjunto de validação pois cada instância deve ser usada para treinar o modelo. Além disso o conjunto de teste que seria usado pode não ter poder preditivo suficiente para tomar deciões precisas. Muitos pesquisadores reportaram que usar apenas um conjunto de dados é uma decisão pobre em termos de performance. Usar a validação cruzada é uma alternativa melhor e viável.

Se um conjunto de teste é estritamente necessário podemos tomar algumas ações:

  1. Podemos treinar o modelo com um conjunto e testar em outro
  2. No mundo de SPAM de e-mails os mais novos são mais importantes que os mais antigos.

Na maioria dos casos não há desejo em transformar os conjuntos de treino e teste em homogeneos, Amostragens aleatórias podem ser usadas para criar datasets equivalentes.

A forma mais simples para criar conjuntos de treino/teste é tomar amostras aleatórias, não considera informação sobre desbalanceamento entre classes, quando ocorre desbalancemento a distribuição entre classes do output do modelo pode variar muito entre o treino/teste.

Uma alternativa é usar uma amostragem estratificada ao separar os dados, que é uma amostra aleatória aplicada em subgrupos (acredito que aqui seja o upsampling e downsampling)

Os dados também podem ser divididos entre os valores das variáveis preditoras, uma proposta aceita na literatura é maximizar a dissimilaridade amostral. Há muitas formas para calcular a dissimilaridade amostral a mais comum é usar a distância entre dois pontos de um mesmo preditor, se a distância é pequena os pontos estão próximos, caso contrário estão longe (indicador de dissimilaridade). Para usar esse conceito como ferramenta suponha que o conjunto de teste foi inicializado com apenas uma instância. A dissimilaridade entre esse ponto e os pontos não alocados pode ser calculada. O ponto não alocado com maior dissimilaridade deve ser adicionado ao conjunto de teste. Para adicionar mais pontos será necessário um método para calcular a dissimilaridade entre um ponto e um conjunto, uma abordagem é usar o valor médio de dissimilaridade.

Calcula-se a dissimilaridade média dos pontos adicionados ao conjunto de dados, depois escolhemos o ponto (no conjunto não alocado) com maior dissmilaridade em relação a média de dissimilaridade do conjunto adicionado e adicionamos ele ao conjunto alocado esse processo continua até atingirmos o tamanho do conjunto de teste desejado.

A Figura abaixo mostra esse processo aplicado em um problema de classificação de dados, nesse tipo de problema a técnica de maximização é aplicada dentro de cada classe separadamente, nesse exemplo não foi usada a média entre grupos mas sim o mínimo.

Maximização de dissimilaridade para classificação

Maximização de dissimilaridade para classificação

Técnicas de reamostragem

De uma maneira geral técnicas de reamostragem usadas para avaliar a performance do modelo trabalham de forma parecida. Uma parte dos dados é usada para fitar o modelo e a outra é usada para testar a eficácia dos dados, esse processo é repetido diversas vezes os resultados são sumarizados e agregados. A diferença das tecnicas de reamostragem residem na forma como as subamostras são selecionados.

k-Fold Cross-validation

As instâncias são divididas em k partições com tamanhos aproximados, um modelo é fitado usando 9 partições e testado com a última. Esse processo é repetido 10 vezes trocando a partição de teste por uma que nunca foi usada para teste, na figura abaixo notamos um 3-fold cross-validation: Bootstrap Uma variação dessa estratégia é fazer uma amostragem estratíficada por classes em cada um dos folds. Outra variação, leave one out cross-validation (LOOCV), é um caso especial onde k é igual ao número de instâncias, removemos uma e treinamos com as outras. O modelo final é calculado pela sumarização das k instâncias deixadas de fora uma a uma.

Não há definição formal sobre qual o melhor valor de k tipicamente são usados os valores \({5, 10}\) quanto maior o valor de k menor o bias da técnica. Com o aumento de k a diferença entre conjuntos de treino e teste reduz.

Um ponto importante sobre técnicas de reamostragem é incerteza (variação/ruído), um método sem viés pode predizer o valor correto mas paga um preço alto para isso, incerteza. O que significa que repetir o processo de re amostragem pode produzir resultados distintos. Validação cruzada possuí alta variação comparada a outras técnicas, porém para grandes conjuntos de treino essa variância pode ser desprezada.

Valores grandes de k são computacionalmente onerosos, LOOCV é o mais computacionalmente intenso dentre todas as técnicas pois necessita de um modelo distinto para cada ponto e cada subconjunto tem o tamanho da amostra menos um. Tem pesquisas que mostram que o leave one out é tão efetivo quanto uma validação cruzada para \(k=10\). Valores pequenos de k tem um bias alto mas são menos computacionalmente onerosos, esse bias é quase o mesmo obtido por um bootstrap porém com uma variância muito maior.

Generalizae Cross-validation

Para modelos lineares de regressão para aproximar o erro do leave-one-out. O generalized Cross-validation (GCV) estatística não exige refitar o modelo para cada subamostra \[ GCV = \frac{1}{n} \sum_{i=1}^{n} \frac{y_i - \hat{y_i}}{1 - \frac{df}{n}} \] onde \(y_i\) é o i-ésimo rótulo, \(\hat{y_i}\) é a i-ésima predição do modelo e \(df\) são os graus de liberdade do modelo (parâmetros estimados pelo mesmo) que é uma medida de complexidade para modelos lineares. Dois modelos com a mesma soma de erro quadrado terão diferentes GCV se a complexidade dos modelos forem distintas. Vale ressaltar que é uma fórmula fechada.

Repeated Training/Test Splits

É conhecido por leave-group-out cross-validation, monte carlo cross-validation, cria muitas divisões dos dados de treino e teste, a proporção de dados para cada subamostra e o número de repetições são controlados pelo analista. Como falamos anteriormente, o bias reduz conforme a quantidade de dados na amostra se aproxima do conjunto de modelagem valores tipicamente usados são: 75% - 80% . A figura abaixo exemplifica esse esquema: Repeated Training/Test Splits

Pode-se observar que a diferença fundamental entre essa estratégia e a validação cruzada é que pode haver repetição de instâncias podem ser representadas em vários grupos deixados para predizer. Além disso o número de repetições aqui tende a ser muito maior que uma validação cruzada.

O número e repetições é importante pois ao aumentarmos ele decrementamos a incerteza do modelo. Para resultados com alta instabilidade 20 repetições seriam suficientes, para obter um score mais estável podemos colocar 50-200 repetições. Esse valor é uma proporção dos exemplos sendo alocados no conjunto de predição, quanto maior a porcentagem mais repetições serão necessárias para reduzir a incerteza do modelo

Bootstrap

É uma amostragem com reposição, ou seja, após um ponto ser selecionado para o fold/set ele ainda fica disponível para ser reselecionado novamente. Uma amostra de bootstrap tem o mesmo tamanho do dataset original, como resultado direto alguns pontos serão selecionados mais de uma vez e outros não serão selecionados. Os pontos não selecionados são conhecidos por out-of-bag, uma iteração de bootstrap usa os exemplos selecionados para treinar o modelo e os out-of-bag para testar. Na figura abaixo podemos ver um exemplo disso:

Bootstrap

Bootstrap

De uma forma geral as taxas de erro de bootstrap tem menos incerteza que um k-fold, entretanto \(63.25\%\) dos pontos são representados pelo menos uma vez, portanto essa técnica tem um bias similar ao k-fold para \(k=2\). Se o conjunto de treino for pequeno esse bias é grande caso contrário pode ser desprezado.

Alguns métodos foram propostos para reduzir esse bias, um deles é conhecido por 632 method que é uma combinação de um booststrap simples com uma repredição do conjunto de treino. Por exemplo um modelo de classificação usando esse método seria: \[ (0.632 \times \textrm{bootstrap estimate}) + (0.368 \times \textrm{apparent error rate}) \] Esse novo bootstrap reduz o bias mas pode ser instável para amostras pequenas. Essa estimação pode resultar em resultados indevidamente otimistas quando o modelo overfita gravemente. Uma técnica nova foi realizada para ajustar a estimativa de erro do bootstrap denominada 632+method

Estudo de caso: Scoragem de crédito

Pode-se aplicar modelos estatísticos para escoragem de crédito. Dados existentes podem ser usados para criar um modelo que prediga se um aplicante à crédito tem bom crédito ou não. Essa informação pode ser usada para definir o risco do banco que está emprestando dinheiro.

German credit data é um dataset muito usado para atividades de ML, contém \(1000\) instâncias, rótulos de bom e mal pagador. O dataset é desbalancedo pois \(70\%\) são bons pagadores. Se chutassemos todos os exemplos como sendo: bom pagador teríamos uma acurácia de \(70\%\), portanto o baseline usado de acurácia deve ser no mínimo \(70\%\). (Eu discordo dos autores, essa abordagem é viável mas seria mais simples usar um F1 por exemplo)

Alguns preditores são numéricos mas a maioria é categorica, as categoricas foram binarizadas, \(800\) instâncias serão usadas para treino e \(200\) para teste. O objetivo desse capítulo é ilustrar como tunar um modelo usando reamostragem.

Encontrando os parâmetros finais

Como escolher o melhor modelo? Uma idéia é pegar o que tiver o melhor score e usar. Um modelo não linear SVM foi fitado para valores de custo entre \(2^{-2}\) até \(2^{7}\). Cada modelo foi testado com cinco repetições de 10-fold cross-validation as figuras abaixo mostram os valores de acurácia para

acurácia x valor do custo

acurácia x valor do custo

acurácia x valor do custo

acurácia x valor do custo

Para cada modelo foram gerados 50 estimativas da acuráciaos pontos vermelhos do gráficos são as médias dessas estimativas as barras são 2 \(\pm\) desvios padrão da média do erro. O profile de treinamento mostra um incremento na acurácia até o valor de custo 8 depois disso temos um decréscimo contínuo indicando um overfitting. Perceba que pela acurácia aparente o modelo melhora a medidad que o custo aumenta até 8, depois ocorre um overfitting.

Escolher o ponto de ótimo para o modelo pode não ser um boa idéia dado que são preferíveis modelos mais simples do que os complexos. Uma abordagem diferente é one-standard error que encontra o valor de ótimo e ao mesmo tempo seu erro padrão, em seguida procura o modelo mais simples com distância de um erro padrão do melhor valor numérico. Na figura abaixo podemos ver que o valor de acurácia para custo 8 é \(0.7\%\) essa técnica encontrará o melhor modelo com acurácia não menos que \(74.3%\) (\(75\% - 0.7\%\)) escolhendo o valor de custo \(2\).

Outra abordagem é escolher um modelo mais simples dentro de uma certa tolerância do valor numérico ótimo. O percentual de descréscimo da performance pode ser calculado por \((X-O)/O\) onde \(X\) é a performance e \(O\) é o valor numérico ótimo. Por exemplo, na figura com o custo do SVM a melhor acurácia de acordo com o profile foi \(75\%\) se uma perda de 4 na acurácia for aceitável, como trade off para um modelo mais simples, valores de acurácia maiores que \(71.2\%\) poderiam ser aceitos, um valor de custo \(1\) poderia ser aceito nesse modelo.

Na figura abaixo foram testados diversos métodos de reamostragem entre eles: 10-fold cross-validation, LOOCV, repeated cross-validation, bootstrap (com e sem ajuste \(632\)) e repeated training/test split (\(20\%\) de held-out). Os últimos dois usando reamostragem de 50 para estimar a performance.

Bootstrap

Bootstrap

Todas as validações cruzadas apresentam um padrão de ponto ótimo entre \(4\) e \(16\) seguidos de uma queda de desempenho, muito provável overfitting. Com excessão do bootstrap \(632\) todas as técnicas tem um pico, que é atingido rapidamente, seguido pela queda do overfitting. As técnicas de cross-validation tem acurácia entre \(74.5\%\) \(76.6\%\). O bootstrap simples tem o pior desempenho \(74.2\%\) e o bootstrap \(632\) super compensa o bias e estima com \(82.3\%\) de acurácia.

A largura do erro padrão do 10-fold cross-validation é a maior de todas pois o erro padrão é uma função do número de reamostragens usadas (10 versus as 50 usadas pelo bootstrap). A velocidade de computação o método mais rápido é: 10-fold cross validation, em seguida temos, quase empatados, repeated cross validation, bootstrap e repeated training/test e LOOCV é o mais demorado.

Data Split recomendações

Pontos negativos em usar um conjunto de teste único e independente:

1 - É uma validação única e não avalia incertezas nos resultados 2 - Proporcionalmente conjuntos de dados grandes aumentam o bias da estimativa de performance 3 - Com conjuntos de dados pequenos: 3a - O modelo necessitará de todos os pontos para estimar corretamente 3b - A incerteza do conjunto de teste pode ser conisderavelmente maior dado que conjuntos de teste distintos produzem resultados diferentes 4 - metodos de reamostragem produzem resultados aceitáveis de como o modelo vai performar no futuro

Não existe um método melhor que outro, há diversas situações onde devem ser avaliados os trade-offs. Para conjuntos de dados pequenos é melhor um 10-fold cross-validation pois o bias e variância serão ok e o custo computacional, dado o tamanho da amostra, não será elevado. Se o objetivo é escolher entre modelos em oposição a escolher o melhor indicador de performance, seria recomendável escolher uma técnica de bootstrap pois sua variância é baixa. Para conjuntos de dados grandes a diferença entre métodos se torna irrelevante e escolhemos entre poder computacional tipo um 10-fold cross-validation (discordo do autor, devemos usar um método para obter o melhor modelo mesmo que demore a execução).

Escolhendo entre modelos

Depois de escolher os parâmetros ótimos para cada modelo, devemos escolher qual o melhor modelo entre todos. Essa tarefa é bem complexa, para tal, devemos seguir o seguinte procedimento:

1 - Começar com modelos complexos como SVM, Boosted tree que produzem resultados ótimos 2 - Usar modelos mais simples e quase interpretáveis MARS, partial least squares, generalized aditive models, naive bayes 3 - Considere usar o modelo mais simples possível dentro da performance esperada (é um trade-off).

Dessa forma, podemos achar o teto de performance e depois ponderar até onde podemos perder de precisão para ganhar em interpretabilidade. No geral a maioria dos modelos tem resultados próximos então podemos escolher de acordo com os benefícios das diferentes metodologias. Complexidade, interpretabilidade, facilidade em predizer. Um SVM e random forest tem acurácia excelente porém suas complexidades computacionais podem impedir de colocarmos eles em produção, se um MARS tiver desempenho levemente inferior podemos usar ele pois tem um tempo de execução muito inferior.

Considerando o exemplode scoragem de crédito onde usamos um SVM com repeated 10-fold cross-validation a acurácia estimada do modelo era de \(75\%\) com a maioria dos resultados de reamostragem entre \(66\%\) e \(82\%\). Usando uma logistica com o mesmo schema de cross-validation obtivemos \(74.9\%\) com a maioria dos resultados de reamostragem entre \(66\%\) e \(82\%\). As mesmas \(50\) reamostragens foram usadas para avaliar cada modelo, a figura abaixo mostra a distribuição de ambos

Bootstrap

Bootstrap

Dado que a acurácia foi metrificada usando o mesmo conjunto de dados reamostrado da mesma forma, estatísticas para comparasão em pares podem ser usadas para determinar se as diferenças entre modelos é estatisticamente significante. Um t-test pareado pode ser usado para comparar se a acurácia (média) dos modelos, ou a diferença média na acurácia dos data sets reamostrados é zero. Para ambos os modelos a diferença média na acurácia dos modelos foi de \(0.1\%\) com a logistica tendo resultados melhores. O intervalo de confiança de \(95\%\) foi de (\(-1.2\%\), \(1\%\)) indicando que a acurácia de nenhum dos modelos é significantemente melhor.

Quando são usadas várias metodologias para comparar modelos podemos chegar em situações conflitantes, dependendo do problema a ser tratado devemos considerar o peso de uma estatística maior que de outro. Especificidade e sensitividade podem ser usados para comparar modelos. Se o conjunto de dados tem mais eventos que não eventos sensitividade pode ser usado melhor que especificidade. Com aumento de precisão há uma verissimilhança maior que modelos podem ser diferenciados em termos de sensitividade do que especificidade.

Computação :)

LS0tCnRpdGxlOiAiRGF0YSBQcmUtcHJvY2Vzc2luZyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBDSDA0IC0gT3ZlciBGaXR0aW5nIGFuZCBtb2RlbCB0dW5uaW5nCk1vZGVsb3MgYXR1YWlzIGNvbnNlZ3VlbSByZXByZXNlbnRhciBxdWFpc3F1ZXIgcGFkcsO1ZXMgbm9zIGRhZG9zLCBpbmZlbGl6bWVudGUgZWxlcyBwb2RlbSBvdmVyIGZpdGFyIChyZXByZXNlbnRhciBwYWRyw7VlcyBxdWUgbsOjbyBzw6NvIHJlcHJvZHV6aXZlaXMgbm8gZGVjb3JyZXIgZG8gdGVtcG8pLCBwYXJhIGF2YWxpYXIgbW9kZWxvcyBwcmVjaXNhbW9zIGRlIHVtYSBtZXRvZG9sb2dpYSBzaXRlbcOhdGljYS4gTmVzc2UgY2Fww610dWxvIHNlcsOjbyBkZXNjcml0YXMgdMOpY25pY2FzIHBhcmEgZ2FyYW50aXIgdW0gbWVzbW8gcmVzdWx0YWRvIHBhcmEgbW9kZWxvcyBubyBkZWNvcnJlciBkbyB0ZW1wbyBlIGV2aXRhciBvdmVyZml0LiBOZXNzZSBjYXDDrXR1bG8gYXNzdW1lLXNlIHF1ZSBvcyBkYWRvcyBzw6NvIHJlcHJlc2VudGF0aXZvcyBkYSBwb3B1bGHDp8OjbyBlIHF1ZSBow6EgdW1hIHF1YWxpZGFkZSBtw61uaW1hIG5hIHByb3ZlbmnDqm5jaWEgZGUgZGFkb3MgZGFzIGFtb3N0cmFzLgoKQ29tIGVzc2FzIGNvbmRpw6fDtWVzLCBub3NzbyBvYmpldGl2byDDqSB0dW5hciBvIG1vZGVsbyBzZW0gb3ZlcmZpdGEtbG8uIFBhcmEgdGFsIGRpdmlkaW1vcyBvIGNvbmp1bnRvIGRlIGRhZG9zIGVtIHRyZWluby90ZXN0ZSwgYWJvcmRhZ2VucyBtYWlzIG1vZGVybmFzIGRpdmlkZW0gZW0gdsOhcmlvcyBjb25qdW50b3MgZGUgdHJlaW5vL3Rlc3RlIHBhcmEgYXRpbmdpciB1bSByZXN1bHRhZG8gbWVsaG9yIGRvIG1vZGVsby4KCiMjI1RoZSBwcm9ibGVtIG9mIG92ZXItZml0dGluZwpUw6ljbmljYXMgcXVlIGFwcmVuZGVtIG11aXRvIGJlbSBhIGVzdHJ1dHVyYSBkb3MgZGFkb3MgdMOjbyBiZW0gcXVlIGFvIHNlciBhcGxpY2FkbyBub3MgZGFkb3Mgb25kZSBvIG1vZGVsbyBmb2kgY29uc3RydcOtZG8gcHJlZGl6IGNvcnJldGFtZW50ZSAkMTAwJSQgZGEgYW1vc3RyYS4gQWzDqW0gZGUgYXByZW5kZXIgb3MgcGFkcsO1ZXMgZ2VyYWlzIGRlIGNvbXBvcnRhbWVudG8gZG9zIGRhZG9zIG8gbW9kZWxvIGFwcmVuZGV1IG8gcnXDrWRvIGRlIGNhZGEgZGFkbywgaXNzbyBzaWduaWZpY2EgcXVlIG8gbW9kZWxvICpvdmVyZml0b3UqIAoKIVtDb25qdW50byBkZSB0cmVpbm8gY29tIGRvaXMgcHJlZGl0b3Jlc10oLi9DaDA0RmlnMDEucG5nKQoKQSBmaWd1cmEgYWNpbWEsIHNlcsOhIHVzYWRhIHBhcmEgaWx1c3RyYXIgbyBjb25jZWl0byBkZSBvdmVyLWZpdHRpbmcsIGNvbnTDqW0gJDIwOCQgZXhlbXBsb3MgZSDDqSB1bSBwcm9ibGVtYSBkZSBjbGFzc2lmaWNhw6fDo28gYmluw6FyaWEsIGNvbSBkdWFzIHZhcmnDoXZlaXMgcHJlZGl0b3Jhcy4gSMOhIHVtIGxldmUgZGVzYmFsYW5jZWFtZW50byBuYXMgY2xhc3NlcyAkMTExJCBjbGFzc2UgMSBlICQ5NyQgY2xhc3NlIDIgYWzDqW0gZGlzc28gZXhpc3RlIHVtYSBzb2JyZXBvc2nDp8OjbyBkZSBjbGFzc2VzLCB1bSBwcm9ibGVtYSB0aXBpY2FtZW50ZSBlbmNvbnRyYWRvLiBVbSBtb2RlbG8gcXVlIHVzZSBlc3NlcyBkYWRvcyB0ZW0gdGlwaWNhbWVudGUgdW0gb2JqZXRpdm86ICpwcmVkaXplciBub3ZvcyBkYWRvcyosIG8gbW9kZWxvIHBvZGUgc2VyIHJlcHJlc2VudGFkbyBjb21vIHVtIGZyb250ZWlyYShzKSBkZSBkZWNpc8OjbyjDtWVzKS4KCiFbRnJvbnRlaXJhcyBkZSBkZWNpc8Ojb10oLi9DaDA0RmlnMDIucG5nKQoKQSBmaWd1cmEgYWNpbWEgbW9zdHJhIGRvaXMgcG9zc8OtdmVpcyBtb2RlbG9zIHBhcmEgc29sdWNpb25hciBlc3NlIHByb2JsZW1hLCBvIHByaW1laXJvIHNlcGFyYSBjYWRhIGNvbmp1bnRvIGRlIGRhZG9zIGRhIGNsYXNzZSAxIGUgYWxlZ2EgcXVlIG8gcmVzdGFudGUgc2VyaWEgZGEgY2xhc3NlIDIuIFBvZGVtb3MgcGVyY2ViZXIgcXVlIGVzc2UgcGFkcsOjbyBuw6NvIMOpIG11aXRvIGdlbmVyYWxpesOhdmVsLiBPIG1vZGVsbyBkYSBkaXJlaXRhLCBhcHJlc2VudGEgdW1hIGZyb250ZWlyYSBkZSBkZWNpc8OjbyBtZW5vcyByw61naWRhIHF1ZSBuw6NvIGNsYXNzaWZpY2EgY29ycmV0YW1lbnRlIHRvZG9zIG9zIHBvbnRvcywgbWFzIHRlbSBtYWlvciBwcm9iYWJpbGlkYWRlIGRlIGdlbmVyYWxpemFyLgoKTmVzc2UgZXhtcGxvIHNpbXBsaXN0YSwgY29tIGFwZW5hcyBkdWFzIHZhcmnDoXZlaXMsIMOpIHNpbXBsZXMgb2JzZXJ2YXIgbyBvdmVyLWZpdHRpbmcgZG8gbW9kZWxvIGRhIGVzcXVlcmRhLiBObyBtdW5kbyByZWFsIG1vZGVsb3MgdGVtIG11aXRhcyBvdXRyYXMgdmFyacOhdmVpcyB0b3JuYW5kbyBlc3NhIGFib3JkYWdlbSB2aXN1YWwgaW1wcmF0aWPDoXZlbC4gTmVjZXNzaXRhbW9zIGRlIHVtYSBmZXJyYW1lbnRhIHBhcmEgYXZlcmlndWFyIG8gZ3JhdSBkZSBvdmVyLWZpdHRpbmcuCgojIyNNb2RlbCB0dW5uaW5nCk11aXRvcyBtb2RlbG9zIHRlbSBwYXLDom1ldHJvcyBpbXBvc3PDrXZlaXMgZGUgc2VyZW0gZXN0aW1hZG9zIHVzYW5kbyBvcyBkYWRvcywgY29tbyBvIEtOTiwgZGV2ZW1vcyBpbmZvcm1hciBvIG7Dum1lcm8gZGUgdml6aW5ob3MuIEFvIGVzY29saGVyIG11aXRvcyB2aXppbmhvcyBwb2RlbW9zIG7Do28gY29uc2VndWlyIGFwcmVuZGVyIG8gc3VmaWNpZW50ZSBkb3MgZGFkb3MsIGFvIGVzY29saGVyIHBvdWNvcyBwb2RlbW9zIGZhY2lsbWVudGUgb3Zlci1maXR0YXIuIEVzc2UgdGlwbyBkZSBwYXLDom1ldHJvIMOpIGNvbmhlY2lkbyBwb3I6ICpwYXLDom1ldHJvIGRlIHR1bm5pbmcqIG11aXRvcyBtb2RlbG9zIGFwcmVzZW50YW0gcGVsbyBtZW5vcyB1bSBkZXNzZXMgcGFyw6JtZXRyb3MuCiFbRnJvbnRlaXJhcyBkZSBkZWNpc8Ojb10oLi9DaDA0RmlnMDMucG5nKQoKQSBlc2NvbGhhIGRlc3NlcyBwYXLDom1ldHJvcyBhdW1lbnRhbSBvdSByZWR1emVtIG8gZ3JhdSBkZSBlc3BlY2lhbGl6YcOnw6NvIGRvIG1vZGVsbywgcG9kZW5kbywgY2F1c2FyIG92ZXItZml0dGluZy4gUE9yIGV4ZW1wbG8gbyBwYXLDom1ldHJvIGN1c3RvIGRvIFNWTSAqQyogcXVlIGluZm9ybWEgbyBwZXNvIGRvIGVycm8gZGUgY2xhc3NpZmljYcOnw6NvIGRvIG1vZGVsbywgYW8gc2V0YXIgdW0gdmFsb3IgZ3JhbmRlIHBhcmEgZXNzZSBwYXLDom1ldHJvLCB0ZW1vcyB1bSBtb2RlbG8gYWx0YW1lbnRlIG92ZXItZml0dGFkbyBlbnF1YW50byBxdWUgdW0gdmFsb3IgYmFpeG8gaW5kaWNhIHVtIG1vZGVsbyBjb20gcmVzdWx0YWRvcyBiYWl4b3MuIE5vIHBhaW5lbCBkYSBkaXJlaXRhIGRhIGZpZ3VyYSBmcm9udGVpcmFzIGRlIGRlY2lzw6NvIGZvaSBlc2NvbGhpZG8gdW0gdmFsb3IgYWx0bywgbm8gcGFpbmVsIGRhIGVzcXVlcmRhIGZvaSBlc2NvbGhpZG8gdW0gdmFsb3IgdXNhbmRvIHZhbGlkYcOnw6NvIGNydXphZGEuCgpVbWEgYWJvcmRhZ2VtIHBhcmEgZXNjb2xoYSBkZSBwYXLDom1ldHJvcyDDqSBzZWxlY2lvbmFyIHVtIHN1YmNvbmp1bnRvIGRlbGVzLCB0cmVpbmFyIGRpdmVyc29zIG1vZGVsb3MgZSBvYnNlcnZhciBvIG1lbGhvciBlbnRyZSBlbGVzLgpFc3NlIHByb2Nlc3NvIHBvZGUgc2VyIHZpc3VhbGl6YWRvIG5hIGZpZ3VyYSBhYmFpeG86CiFbRnJvbnRlaXJhcyBkZSBkZWNpc8Ojb10oLi9DaDA0RmlnMDQucG5nKQoKCkFww7NzIHNlbGVjaW9uYXIgdW0gY29uanVudHRvIGRlIHBhcsOibWV0cm9zIGFjZWl0w6F2ZWlzIHBhcmEgdHJlaW5hcm1vcyBvIG1vZGVsbyBkZXZlbW9zIGVuY29udHJhciB1bWEgbcOpdHJpY2EgKGNvbmZpw6F2ZWwpIHBhcmEgYXZhbGlhcm1vcyBzdWEgcGVyZm9ybWFuY2UuIE5lc3NlIHBvbnRvIGFwbGljYW1vcyB1bWEgZXN0cmF0w6lnaWEgZGUgZm9yw6dhIGJydXRhIG5vcyBkYWRvcyBlIG5vcyBwYXLDom1ldHJvcyBwYXJhIGVuY29udHJhcm1vcyBvIG1lbGhvciBtb2RlbG8gZSBwYXLDom1ldHJvLiBPdXRyYXMgYWJvcmRhZ2VucyBwYXJhIGVuY29udHJhciBvcyBwYXLDom1ldHJvcyDDs3RpbW8gc8OjbyB1c2FyIGFsZ29yaXRtb3MgZ2Vuw6l0aWNvcyBvdSBtw6l0b2RvcyBkZSBkZSBidXNjYSBiYXNlYWRvcyBlbSBzaW1wbGV4LgoKTyBtYWlvciBwcm9ibGVtYSDDqSBlbmNvbnRyYXIgdW1hIGVzdGltYXRpdmEgY29uZmnDoXZlbCBwYXJhIGVzc2VzIG1vZGVsb3MgZSBkZWZpbmlyIHF1YWwgbyBtZWxob3IgZGVudHJlIGVsZXMsIGNvbW8gdmltb3MgYW50ZWlvcm1lbnRlIHRheGEgZGUgZXJybyBwb2RlIG5vcyBsZXZhciBhIHVtYSBmYWxzYSBzZW5zYcOnw6NvIGRlIHNlZ3VyYW7Dp2EuIFVtYSBhYm9yZGFnZW0gdXNhZGEgw6kgdGVzdGFyIG8gbW9kZWxvIHBhcmEgdW1hIGFtb3N0cmEgbsOjbyB1c2FkYSBwYXJhIHRyZWluYXIgbyBtZXNtbywgc2V1IHRhbWFuaG8gZGV2ZSBzZXIgY29uc2lkZXLDoXZlbC4KClVtYSBvdXRyYSBhYm9yZGFnZW0gw6kgdXNhciB1bSBjb25qdW50byBhcGVuYXMgZGUgdGVzdGUgcmVhbW9zdHJhbmRvIG8gY29uanVudG8gZGUgdHJlaW5hbWVudG8sIHBhcmEgcmVhbGl6YXIgaXNzbyBleGlzdGVtIGFsZ3VtYXMgdMOpY25pY2FzIGVzdGF0w61zdGljYXMgcXVlIHNlcsOjbyBhYm9yZGFkYXMgYWRpYW50ZS4KCgojIyNEaXZpc8OjbyBkZSBkYWRvcwpPIGNvcmHDp8OjbyBkbyBwcm9jZXNzbyBwYXJhIGVuY29udHJhciBvcyBwYXLDom1ldHJvcyDDs3RpbW8gw6kgYSBkaXZpc8OjbyBkbyBjb25qdW50byBkZSBkYWRvcywgYSBjb25zdHJ1w6fDo28gZG8gbW9kZWxvIHNlZ3VlIG9zIHNlZ3VpbnRlcyBwYXNzb3M6CgoxLiBQcsOpLXByb2Nlc3NhbWVudG8gZG9zIHByZWRpdG9yZXMKMi4gRXN0aW1hw6fDo28gZG9zIHBhcsOibWV0cm9zCjMuIFNlbGXDp8OjbyBkZSBwcmVkaXRvcmVzCjQuIEF2YWxpYcOnw6NvIGRhIHBlcmZvcm1hbmNlCjUuIEFqdXN0ZSBmaW5vIGRhcyByZWdyYXMgZGUgY2xhc3NpZmljYcOnw6NvICh0aXBpY2FtZW50ZSB1c2FuZG8gY3VydmFzIFJPQykKCkRhZG8gcXVlIGjDoSB1bSBjb25qdW50byBmaXhvIGRlIHBvbnRvcyBkZSBhbW9zdHJhLCBvIG1vZGVsYWRvciBkZXZlIGRlY2lkaXIgY29tbyBkaXN0cmlidWktbG9zIG5lc3NhcyBldGFwYXMuIEEgcHJpbmNpcGFsIGVzY29saGEgc8OjbyBvcyBwb250b3MgcXVlIHNlcsOjbyB1c2Fkb3MgcGFyYSBhdmFsaWFyIG8gbW9kZWxvLCBpZGVhbG1lbnRlIG7Do28gZGV2ZW0gc2VyIG9zIG1lc21vcyB1c2Fkb3MgcGFyYSB0cmVpbmFyL2FqdXN0YXIgZmluYW1lbnRlIG8gbW9kZWxvLCBkZXNzYSBmb3JtYSwgZWxlcyByZXByZXNlbnRhbSB2YWxvcmVzIG7Do28gdmllc2Fkb3MuIFF1YW5kbyBow6EgdW0gY29uanVudG8gZGUgZGFkb3MgZ3JhbmRlIGUgZXhwcmVzc2l2byBwb2RlbW9zIHNlcGFyYXIgb3MgY29uanVudG9zIGVtIHZhbGlkYcOnw6NvIGUgdGVzdGUgc2VtIHByb2JsZW1hcywgdXNhbmRvIHVtIHBhcmEgKnRyZWluYXIqIGUgb3V0cm8gcGFyYSAqdmFsaWRhciouCgpRdWFuZG8gbsOjbyBow6EgdW0gY29uanVudG8gZGUgZGFkb3MgZ3JhbmRlIG8gc3VmaWNpZW50ZSBuw6NvIGZhemVtb3MgdW0gY29uanVudG8gZGUgdmFsaWRhw6fDo28gcG9pcyBjYWRhIGluc3TDom5jaWEgZGV2ZSBzZXIgdXNhZGEgcGFyYSB0cmVpbmFyIG8gbW9kZWxvLiBBbMOpbSBkaXNzbyBvIGNvbmp1bnRvIGRlIHRlc3RlIHF1ZSBzZXJpYSB1c2FkbyBwb2RlIG7Do28gdGVyIHBvZGVyIHByZWRpdGl2byBzdWZpY2llbnRlIHBhcmEgdG9tYXIgZGVjacO1ZXMgcHJlY2lzYXMuIE11aXRvcyBwZXNxdWlzYWRvcmVzIHJlcG9ydGFyYW0gcXVlIHVzYXIgYXBlbmFzIHVtIGNvbmp1bnRvIGRlIGRhZG9zIMOpIHVtYSBkZWNpc8OjbyBwb2JyZSBlbSB0ZXJtb3MgZGUgcGVyZm9ybWFuY2UuIFVzYXIgYSB2YWxpZGHDp8OjbyBjcnV6YWRhIMOpIHVtYSBhbHRlcm5hdGl2YSBtZWxob3IgZSB2acOhdmVsLgoKU2UgdW0gY29uanVudG8gZGUgdGVzdGUgw6kgZXN0cml0YW1lbnRlIG5lY2Vzc8OhcmlvIHBvZGVtb3MgdG9tYXIgYWxndW1hcyBhw6fDtWVzOgoKMS4gUG9kZW1vcyB0cmVpbmFyIG8gbW9kZWxvIGNvbSB1bSBjb25qdW50byBlIHRlc3RhciBlbSBvdXRybwoyLiBObyBtdW5kbyBkZSBTUEFNIGRlIGUtbWFpbHMgb3MgbWFpcyBub3ZvcyBzw6NvIG1haXMgaW1wb3J0YW50ZXMgcXVlIG9zIG1haXMgYW50aWdvcy4KCk5hIG1haW9yaWEgZG9zIGNhc29zIG7Do28gaMOhIGRlc2VqbyBlbSB0cmFuc2Zvcm1hciBvcyBjb25qdW50b3MgZGUgdHJlaW5vIGUgdGVzdGUgZW0gaG9tb2dlbmVvcywgQW1vc3RyYWdlbnMgYWxlYXTDs3JpYXMgcG9kZW0gc2VyIHVzYWRhcyBwYXJhIGNyaWFyIGRhdGFzZXRzIGVxdWl2YWxlbnRlcy4KCkEgZm9ybWEgbWFpcyBzaW1wbGVzIHBhcmEgY3JpYXIgY29uanVudG9zIGRlIHRyZWluby90ZXN0ZSDDqSB0b21hciBhbW9zdHJhcyBhbGVhdMOzcmlhcywgbsOjbyBjb25zaWRlcmEgaW5mb3JtYcOnw6NvIHNvYnJlIGRlc2JhbGFuY2VhbWVudG8gZW50cmUgY2xhc3NlcywgcXVhbmRvIG9jb3JyZSBkZXNiYWxhbmNlbWVudG8gYSBkaXN0cmlidWnDp8OjbyBlbnRyZSBjbGFzc2VzIGRvIG91dHB1dCBkbyBtb2RlbG8gcG9kZSB2YXJpYXIgbXVpdG8gZW50cmUgbyB0cmVpbm8vdGVzdGUuCgpVbWEgYWx0ZXJuYXRpdmEgw6kgdXNhciB1bWEgYW1vc3RyYWdlbSBlc3RyYXRpZmljYWRhIGFvIHNlcGFyYXIgb3MgZGFkb3MsIHF1ZSDDqSB1bWEgYW1vc3RyYSBhbGVhdMOzcmlhIGFwbGljYWRhIGVtIHN1YmdydXBvcyAoYWNyZWRpdG8gcXVlIGFxdWkgc2VqYSBvIHVwc2FtcGxpbmcgZSBkb3duc2FtcGxpbmcpCgpPcyBkYWRvcyAgdGFtYsOpbSBwb2RlbSBzZXIgZGl2aWRpZG9zIGVudHJlIG9zIHZhbG9yZXMgZGFzIHZhcmnDoXZlaXMgcHJlZGl0b3JhcywgdW1hIHByb3Bvc3RhIGFjZWl0YSBuYSBsaXRlcmF0dXJhIMOpIG1heGltaXphciBhIGRpc3NpbWlsYXJpZGFkZSBhbW9zdHJhbC4gSMOhIG11aXRhcyBmb3JtYXMgcGFyYSBjYWxjdWxhciBhIGRpc3NpbWlsYXJpZGFkZSBhbW9zdHJhbCBhIG1haXMgY29tdW0gw6kgdXNhciBhIGRpc3TDom5jaWEgZW50cmUgZG9pcyBwb250b3MgZGUgdW0gbWVzbW8gcHJlZGl0b3IsIHNlIGEgZGlzdMOibmNpYSDDqSBwZXF1ZW5hIG9zIHBvbnRvcyBlc3TDo28gcHLDs3hpbW9zLCBjYXNvIGNvbnRyw6FyaW8gZXN0w6NvIGxvbmdlIChpbmRpY2Fkb3IgZGUgZGlzc2ltaWxhcmlkYWRlKS4gUGFyYSB1c2FyIGVzc2UgY29uY2VpdG8gY29tbyBmZXJyYW1lbnRhIHN1cG9uaGEgcXVlIG8gY29uanVudG8gZGUgdGVzdGUgZm9pIGluaWNpYWxpemFkbyBjb20gYXBlbmFzIHVtYSBpbnN0w6JuY2lhLiBBIGRpc3NpbWlsYXJpZGFkZSBlbnRyZSBlc3NlIHBvbnRvIGUgb3MgcG9udG9zIG7Do28gYWxvY2Fkb3MgcG9kZSBzZXIgY2FsY3VsYWRhLiBPIHBvbnRvIG7Do28gYWxvY2FkbyBjb20gbWFpb3IgZGlzc2ltaWxhcmlkYWRlIGRldmUgc2VyIGFkaWNpb25hZG8gYW8gY29uanVudG8gZGUgdGVzdGUuIFBhcmEgYWRpY2lvbmFyIG1haXMgcG9udG9zIHNlcsOhIG5lY2Vzc8OhcmlvIHVtIG3DqXRvZG8gcGFyYSBjYWxjdWxhciBhIGRpc3NpbWlsYXJpZGFkZSBlbnRyZSB1bSBwb250byBlIHVtIGNvbmp1bnRvLCB1bWEgYWJvcmRhZ2VtIMOpIHVzYXIgbyB2YWxvciBtw6lkaW8gZGUgZGlzc2ltaWxhcmlkYWRlLgoKQ2FsY3VsYS1zZSBhIGRpc3NpbWlsYXJpZGFkZSBtw6lkaWEgZG9zIHBvbnRvcyBhZGljaW9uYWRvcyBhbyBjb25qdW50byBkZSBkYWRvcywgZGVwb2lzIGVzY29saGVtb3MgbyBwb250byAobm8gY29uanVudG8gbsOjbyBhbG9jYWRvKSBjb20gbWFpb3IgZGlzc21pbGFyaWRhZGUgZW0gcmVsYcOnw6NvIGEgbcOpZGlhIGRlIGRpc3NpbWlsYXJpZGFkZSBkbyBjb25qdW50byBhZGljaW9uYWRvIGUgYWRpY2lvbmFtb3MgZWxlIGFvIGNvbmp1bnRvIGFsb2NhZG8gZXNzZSBwcm9jZXNzbyBjb250aW51YSBhdMOpIGF0aW5naXJtb3MgbyB0YW1hbmhvIGRvIGNvbmp1bnRvIGRlIHRlc3RlIGRlc2VqYWRvLgoKQSBGaWd1cmEgYWJhaXhvIG1vc3RyYSBlc3NlIHByb2Nlc3NvIGFwbGljYWRvIGVtIHVtIHByb2JsZW1hIGRlIGNsYXNzaWZpY2HDp8OjbyBkZSBkYWRvcywgbmVzc2UgdGlwbyBkZSBwcm9ibGVtYSBhIHTDqWNuaWNhIGRlIG1heGltaXphw6fDo28gw6kgYXBsaWNhZGEgZGVudHJvIGRlIGNhZGEgY2xhc3NlIHNlcGFyYWRhbWVudGUsIG5lc3NlIGV4ZW1wbG8gbsOjbyBmb2kgdXNhZGEgYSBtw6lkaWEgZW50cmUgZ3J1cG9zIG1hcyBzaW0gbyBtw61uaW1vLgoKIVtNYXhpbWl6YcOnw6NvIGRlIGRpc3NpbWlsYXJpZGFkZSBwYXJhIGNsYXNzaWZpY2HDp8Ojb10oLi9DaDA0RmlnMDUucG5nKQoKIyNUw6ljbmljYXMgZGUgcmVhbW9zdHJhZ2VtCkRlIHVtYSBtYW5laXJhIGdlcmFsIHTDqWNuaWNhcyBkZSByZWFtb3N0cmFnZW0gdXNhZGFzIHBhcmEgYXZhbGlhciBhIHBlcmZvcm1hbmNlIGRvIG1vZGVsbyB0cmFiYWxoYW0gZGUgZm9ybWEgcGFyZWNpZGEuIFVtYSBwYXJ0ZSBkb3MgZGFkb3Mgw6kgdXNhZGEgcGFyYSBmaXRhciBvIG1vZGVsbyBlIGEgb3V0cmEgw6kgdXNhZGEgcGFyYSB0ZXN0YXIgYSBlZmljw6FjaWEgZG9zIGRhZG9zLCBlc3NlIHByb2Nlc3NvIMOpIHJlcGV0aWRvIGRpdmVyc2FzIHZlemVzIG9zIHJlc3VsdGFkb3Mgc8OjbyBzdW1hcml6YWRvcyBlIGFncmVnYWRvcy4gQSBkaWZlcmVuw6dhIGRhcyB0ZWNuaWNhcyBkZSByZWFtb3N0cmFnZW0gcmVzaWRlbSBuYSBmb3JtYSBjb21vIGFzIHN1YmFtb3N0cmFzIHPDo28gc2VsZWNpb25hZG9zLgoKCiMjI2stRm9sZCBDcm9zcy12YWxpZGF0aW9uCkFzIGluc3TDom5jaWFzIHPDo28gZGl2aWRpZGFzIGVtICprKiBwYXJ0acOnw7VlcyBjb20gdGFtYW5ob3MgYXByb3hpbWFkb3MsIHVtIG1vZGVsbyDDqSBmaXRhZG8gdXNhbmRvIDkgcGFydGnDp8O1ZXMgZSB0ZXN0YWRvIGNvbSBhIMO6bHRpbWEuIEVzc2UgcHJvY2Vzc28gw6kgcmVwZXRpZG8gMTAgdmV6ZXMgdHJvY2FuZG8gYSBwYXJ0acOnw6NvIGRlIHRlc3RlIHBvciB1bWEgcXVlIG51bmNhIGZvaSB1c2FkYSBwYXJhIHRlc3RlLCBuYSBmaWd1cmEgYWJhaXhvIG5vdGFtb3MgdW0gMy1mb2xkIGNyb3NzLXZhbGlkYXRpb246CiFbQm9vdHN0cmFwXSguL0NoMDRGaWcwNi5wbmcpClVtYSB2YXJpYcOnw6NvIGRlc3NhIGVzdHJhdMOpZ2lhIMOpIGZhemVyIHVtYSBhbW9zdHJhZ2VtIGVzdHJhdMOtZmljYWRhIHBvciBjbGFzc2VzIGVtIGNhZGEgdW0gZG9zIGZvbGRzLiBPdXRyYSB2YXJpYcOnw6NvLCBsZWF2ZSBvbmUgb3V0IGNyb3NzLXZhbGlkYXRpb24gKExPT0NWKSwgw6kgdW0gY2FzbyBlc3BlY2lhbCBvbmRlIGsgw6kgaWd1YWwgYW8gbsO6bWVybyBkZSBpbnN0w6JuY2lhcywgcmVtb3ZlbW9zIHVtYSBlIHRyZWluYW1vcyBjb20gYXMgb3V0cmFzLiBPIG1vZGVsbyBmaW5hbCDDqSBjYWxjdWxhZG8gcGVsYSBzdW1hcml6YcOnw6NvIGRhcyBrIGluc3TDom5jaWFzIGRlaXhhZGFzIGRlIGZvcmEgdW1hIGEgdW1hLgoKTsOjbyBow6EgZGVmaW5pw6fDo28gZm9ybWFsIHNvYnJlIHF1YWwgbyBtZWxob3IgdmFsb3IgZGUgKmsqIHRpcGljYW1lbnRlIHPDo28gdXNhZG9zIG9zIHZhbG9yZXMgJHs1LCAxMH0kIHF1YW50byBtYWlvciBvIHZhbG9yIGRlICprKiBtZW5vciBvIGJpYXMgZGEgdMOpY25pY2EuIENvbSBvIGF1bWVudG8gZGUgKmsqIGEgZGlmZXJlbsOnYSBlbnRyZSBjb25qdW50b3MgZGUgdHJlaW5vIGUgdGVzdGUgcmVkdXouCgpVbSBwb250byBpbXBvcnRhbnRlIHNvYnJlIHTDqWNuaWNhcyBkZSByZWFtb3N0cmFnZW0gw6kgaW5jZXJ0ZXphICh2YXJpYcOnw6NvL3J1w61kbyksIHVtIG3DqXRvZG8gc2VtIHZpw6lzIHBvZGUgcHJlZGl6ZXIgbyB2YWxvciBjb3JyZXRvIG1hcyBwYWdhIHVtIHByZcOnbyBhbHRvIHBhcmEgaXNzbywgKmluY2VydGV6YSouIE8gcXVlIHNpZ25pZmljYSBxdWUgcmVwZXRpciBvIHByb2Nlc3NvIGRlIHJlIGFtb3N0cmFnZW0gcG9kZSBwcm9kdXppciByZXN1bHRhZG9zIGRpc3RpbnRvcy4gVmFsaWRhw6fDo28gY3J1emFkYSBwb3NzdcOtIGFsdGEgdmFyaWHDp8OjbyBjb21wYXJhZGEgYSBvdXRyYXMgdMOpY25pY2FzLCBwb3LDqW0gcGFyYSBncmFuZGVzIGNvbmp1bnRvcyBkZSB0cmVpbm8gZXNzYSB2YXJpw6JuY2lhIHBvZGUgc2VyIGRlc3ByZXphZGEuCgpWYWxvcmVzIGdyYW5kZXMgZGUgayBzw6NvIGNvbXB1dGFjaW9uYWxtZW50ZSBvbmVyb3NvcywgTE9PQ1Ygw6kgbyBtYWlzIGNvbXB1dGFjaW9uYWxtZW50ZSBpbnRlbnNvIGRlbnRyZSB0b2RhcyBhcyB0w6ljbmljYXMgcG9pcyBuZWNlc3NpdGEgZGUgdW0gbW9kZWxvIGRpc3RpbnRvIHBhcmEgY2FkYSBwb250byBlIGNhZGEgc3ViY29uanVudG8gdGVtIG8gdGFtYW5obyBkYSBhbW9zdHJhIG1lbm9zIHVtLiBUZW0gcGVzcXVpc2FzIHF1ZSBtb3N0cmFtIHF1ZSBvIGxlYXZlIG9uZSBvdXQgw6kgdMOjbyBlZmV0aXZvIHF1YW50byB1bWEgdmFsaWRhw6fDo28gY3J1emFkYSBwYXJhICRrPTEwJC4gVmFsb3JlcyBwZXF1ZW5vcyBkZSAqayogdGVtIHVtIGJpYXMgYWx0byBtYXMgc8OjbyBtZW5vcyBjb21wdXRhY2lvbmFsbWVudGUgb25lcm9zb3MsIGVzc2UgYmlhcyDDqSBxdWFzZSBvIG1lc21vIG9idGlkbyBwb3IgdW0gYm9vdHN0cmFwIHBvcsOpbSBjb20gdW1hIHZhcmnDom5jaWEgbXVpdG8gbWFpb3IuCgoKIyMjR2VuZXJhbGl6YWUgQ3Jvc3MtdmFsaWRhdGlvbgpQYXJhIG1vZGVsb3MgbGluZWFyZXMgZGUgcmVncmVzc8OjbyBwYXJhIGFwcm94aW1hciBvIGVycm8gZG8gbGVhdmUtb25lLW91dC4gTyBnZW5lcmFsaXplZCBDcm9zcy12YWxpZGF0aW9uIChHQ1YpIGVzdGF0w61zdGljYSBuw6NvIGV4aWdlIHJlZml0YXIgbyBtb2RlbG8gcGFyYSBjYWRhIHN1YmFtb3N0cmEKJCQKR0NWID0gXGZyYWN7MX17bn0gXHN1bV97aT0xfV57bn0gIFxmcmFje3lfaSAtIFxoYXR7eV9pfX17MSAtIFxmcmFje2RmfXtufX0gCiQkCm9uZGUgJHlfaSQgw6kgbyBpLcOpc2ltbyByw7N0dWxvLCAkXGhhdHt5X2l9JCDDqSBhIGktw6lzaW1hIHByZWRpw6fDo28gZG8gbW9kZWxvIGUgJGRmJCBzw6NvIG9zIGdyYXVzIGRlIGxpYmVyZGFkZSBkbyBtb2RlbG8gKHBhcsOibWV0cm9zIGVzdGltYWRvcyBwZWxvIG1lc21vKSBxdWUgw6kgdW1hIG1lZGlkYSBkZSBjb21wbGV4aWRhZGUgcGFyYSBtb2RlbG9zIGxpbmVhcmVzLiBEb2lzIG1vZGVsb3MgY29tIGEgbWVzbWEgc29tYSBkZSBlcnJvIHF1YWRyYWRvIHRlcsOjbyBkaWZlcmVudGVzIEdDViBzZSBhIGNvbXBsZXhpZGFkZSBkb3MgbW9kZWxvcyBmb3JlbSBkaXN0aW50YXMuIFZhbGUgcmVzc2FsdGFyIHF1ZSDDqSB1bWEgZsOzcm11bGEgZmVjaGFkYS4KCiMjI1JlcGVhdGVkIFRyYWluaW5nL1Rlc3QgU3BsaXRzCsOJIGNvbmhlY2lkbyBwb3IgbGVhdmUtZ3JvdXAtb3V0IGNyb3NzLXZhbGlkYXRpb24sIG1vbnRlIGNhcmxvIGNyb3NzLXZhbGlkYXRpb24sIGNyaWEgbXVpdGFzIGRpdmlzw7VlcyBkb3MgZGFkb3MgZGUgdHJlaW5vIGUgdGVzdGUsIGEgcHJvcG9yw6fDo28gZGUgZGFkb3MgcGFyYSBjYWRhIHN1YmFtb3N0cmEgZSBvIG7Dum1lcm8gZGUgcmVwZXRpw6fDtWVzIHPDo28gY29udHJvbGFkb3MgcGVsbyBhbmFsaXN0YS4gQ29tbyBmYWxhbW9zIGFudGVyaW9ybWVudGUsIG8gYmlhcyByZWR1eiBjb25mb3JtZSBhIHF1YW50aWRhZGUgZGUgZGFkb3MgbmEgYW1vc3RyYSBzZSBhcHJveGltYSBkbyBjb25qdW50byBkZSBtb2RlbGFnZW0gdmFsb3JlcyB0aXBpY2FtZW50ZSB1c2Fkb3Mgc8OjbzogNzUlIC0gODAlIC4gQSBmaWd1cmEgYWJhaXhvIGV4ZW1wbGlmaWNhIGVzc2UgZXNxdWVtYToKIVtSZXBlYXRlZCBUcmFpbmluZy9UZXN0IFNwbGl0c10oLi9DaDA0RmlnMDcucG5nKQoKUG9kZS1zZSBvYnNlcnZhciBxdWUgYSBkaWZlcmVuw6dhIGZ1bmRhbWVudGFsIGVudHJlIGVzc2EgZXN0cmF0w6lnaWEgZSBhIHZhbGlkYcOnw6NvIGNydXphZGEgw6kgcXVlIHBvZGUgaGF2ZXIgcmVwZXRpw6fDo28gZGUgaW5zdMOibmNpYXMgcG9kZW0gc2VyIHJlcHJlc2VudGFkYXMgZW0gdsOhcmlvcyBncnVwb3MgZGVpeGFkb3MgcGFyYSBwcmVkaXplci4gQWzDqW0gZGlzc28gbyBuw7ptZXJvIGRlIHJlcGV0acOnw7VlcyBhcXVpIHRlbmRlIGEgc2VyIG11aXRvIG1haW9yIHF1ZSB1bWEgdmFsaWRhw6fDo28gY3J1emFkYS4KCk8gbsO6bWVybyBlIHJlcGV0acOnw7VlcyDDqSBpbXBvcnRhbnRlIHBvaXMgYW8gYXVtZW50YXJtb3MgZWxlIGRlY3JlbWVudGFtb3MgYSBpbmNlcnRlemEgZG8gbW9kZWxvLiBQYXJhIHJlc3VsdGFkb3MgY29tIGFsdGEgaW5zdGFiaWxpZGFkZSAyMCByZXBldGnDp8O1ZXMgc2VyaWFtIHN1ZmljaWVudGVzLCBwYXJhIG9idGVyIHVtIHNjb3JlIG1haXMgZXN0w6F2ZWwgcG9kZW1vcyBjb2xvY2FyIDUwLTIwMCByZXBldGnDp8O1ZXMuIEVzc2UgdmFsb3Igw6kgdW1hIHByb3BvcsOnw6NvIGRvcyBleGVtcGxvcyBzZW5kbyBhbG9jYWRvcyBubyBjb25qdW50byBkZSBwcmVkacOnw6NvLCBxdWFudG8gbWFpb3IgYSBwb3JjZW50YWdlbSAgbWFpcyByZXBldGnDp8O1ZXMgc2Vyw6NvIG5lY2Vzc8OhcmlhcyBwYXJhIHJlZHV6aXIgYSBpbmNlcnRlemEgZG8gbW9kZWxvCgoKIyMjQm9vdHN0cmFwCsOJIHVtYSBhbW9zdHJhZ2VtIGNvbSByZXBvc2nDp8Ojbywgb3Ugc2VqYSwgYXDDs3MgdW0gcG9udG8gc2VyIHNlbGVjaW9uYWRvIHBhcmEgbyBmb2xkL3NldCBlbGUgYWluZGEgZmljYSBkaXNwb27DrXZlbCBwYXJhIHNlciByZXNlbGVjaW9uYWRvIG5vdmFtZW50ZS4gVW1hIGFtb3N0cmEgZGUgYm9vdHN0cmFwIHRlbSBvIG1lc21vIHRhbWFuaG8gZG8gZGF0YXNldCBvcmlnaW5hbCwgY29tbyByZXN1bHRhZG8gZGlyZXRvIGFsZ3VucyBwb250b3Mgc2Vyw6NvIHNlbGVjaW9uYWRvcyBtYWlzIGRlIHVtYSB2ZXogZSBvdXRyb3MgbsOjbyBzZXLDo28gc2VsZWNpb25hZG9zLiBPcyBwb250b3MgbsOjbyBzZWxlY2lvbmFkb3Mgc8OjbyBjb25oZWNpZG9zIHBvciAqb3V0LW9mLWJhZyosIHVtYSBpdGVyYcOnw6NvIGRlIGJvb3RzdHJhcCB1c2Egb3MgZXhlbXBsb3Mgc2VsZWNpb25hZG9zIHBhcmEgdHJlaW5hciBvIG1vZGVsbyBlIG9zICpvdXQtb2YtYmFnKiBwYXJhIHRlc3Rhci4gTmEgZmlndXJhIGFiYWl4byBwb2RlbW9zIHZlciB1bSBleGVtcGxvIGRpc3NvOgoKIVtCb290c3RyYXBdKC4vQ2gwNEZpZzA4LnBuZykKCkRlIHVtYSBmb3JtYSBnZXJhbCBhcyB0YXhhcyBkZSBlcnJvIGRlIGJvb3RzdHJhcCB0ZW0gbWVub3MgaW5jZXJ0ZXphIHF1ZSB1bSBrLWZvbGQsIGVudHJldGFudG8gJDYzLjI1XCUkIGRvcyBwb250b3Mgc8OjbyByZXByZXNlbnRhZG9zIHBlbG8gbWVub3MgdW1hIHZleiwgcG9ydGFudG8gZXNzYSB0w6ljbmljYSB0ZW0gdW0gYmlhcyBzaW1pbGFyIGFvIGstZm9sZCBwYXJhICRrPTIkLiBTZSBvIGNvbmp1bnRvIGRlIHRyZWlubyBmb3IgcGVxdWVubyBlc3NlIGJpYXMgw6kgZ3JhbmRlIGNhc28gY29udHLDoXJpbyBwb2RlIHNlciBkZXNwcmV6YWRvLgoKQWxndW5zIG3DqXRvZG9zIGZvcmFtIHByb3Bvc3RvcyBwYXJhIHJlZHV6aXIgZXNzZSBiaWFzLCB1bSBkZWxlcyDDqSBjb25oZWNpZG8gcG9yICoqNjMyIG1ldGhvZCoqIHF1ZSDDqSB1bWEgY29tYmluYcOnw6NvIGRlIHVtIGJvb3N0c3RyYXAgc2ltcGxlcyBjb20gdW1hIHJlcHJlZGnDp8OjbyBkbyBjb25qdW50byBkZSB0cmVpbm8uIFBvciBleGVtcGxvIHVtIG1vZGVsbyBkZSBjbGFzc2lmaWNhw6fDo28gdXNhbmRvIGVzc2UgbcOpdG9kbyBzZXJpYToKJCQKKDAuNjMyIFx0aW1lcyBcdGV4dHJte2Jvb3RzdHJhcCBlc3RpbWF0ZX0pICsgKDAuMzY4IFx0aW1lcyBcdGV4dHJte2FwcGFyZW50IGVycm9yIHJhdGV9KQokJApFc3NlIG5vdm8gYm9vdHN0cmFwIHJlZHV6IG8gYmlhcyBtYXMgcG9kZSBzZXIgaW5zdMOhdmVsIHBhcmEgYW1vc3RyYXMgcGVxdWVuYXMuIEVzc2EgZXN0aW1hw6fDo28gcG9kZSByZXN1bHRhciBlbSByZXN1bHRhZG9zIGluZGV2aWRhbWVudGUgb3RpbWlzdGFzIHF1YW5kbyBvIG1vZGVsbyBvdmVyZml0YSBncmF2ZW1lbnRlLiBVbWEgdMOpY25pY2Egbm92YSBmb2kgcmVhbGl6YWRhIHBhcmEgYWp1c3RhciBhIGVzdGltYXRpdmEgZGUgZXJybyBkbyBib290c3RyYXAgZGVub21pbmFkYSAqKjYzMittZXRob2QqKgoKCiMjI0VzdHVkbyBkZSBjYXNvOiBTY29yYWdlbSBkZSBjcsOpZGl0bwpQb2RlLXNlIGFwbGljYXIgbW9kZWxvcyBlc3RhdMOtc3RpY29zIHBhcmEgZXNjb3JhZ2VtIGRlIGNyw6lkaXRvLiBEYWRvcyBleGlzdGVudGVzIHBvZGVtIHNlciB1c2Fkb3MgcGFyYSBjcmlhciB1bSBtb2RlbG8gcXVlIHByZWRpZ2Egc2UgdW0gYXBsaWNhbnRlIMOgIGNyw6lkaXRvIHRlbSBib20gY3LDqWRpdG8gb3UgbsOjby4gRXNzYSBpbmZvcm1hw6fDo28gcG9kZSBzZXIgdXNhZGEgcGFyYSBkZWZpbmlyIG8gcmlzY28gZG8gYmFuY28gcXVlIGVzdMOhIGVtcHJlc3RhbmRvIGRpbmhlaXJvLgoKR2VybWFuIGNyZWRpdCBkYXRhIMOpIHVtIGRhdGFzZXQgbXVpdG8gdXNhZG8gcGFyYSBhdGl2aWRhZGVzIGRlIE1MLCBjb250w6ltICQxMDAwJCBpbnN0w6JuY2lhcywgcsOzdHVsb3MgZGUgYm9tIGUgbWFsIHBhZ2Fkb3IuIE8gZGF0YXNldCDDqSBkZXNiYWxhbmNlZG8gcG9pcyAkNzBcJSQgc8OjbyBib25zIHBhZ2Fkb3Jlcy4gU2UgY2h1dGFzc2Vtb3MgdG9kb3Mgb3MgZXhlbXBsb3MgY29tbyBzZW5kbzogKipib20gcGFnYWRvcioqIHRlcsOtYW1vcyB1bWEgYWN1csOhY2lhIGRlICQ3MFwlJCwgcG9ydGFudG8gbyBiYXNlbGluZSB1c2FkbyBkZSBhY3Vyw6FjaWEgZGV2ZSBzZXIgbm8gbcOtbmltbyAkNzBcJSQuIChFdSBkaXNjb3JkbyBkb3MgYXV0b3JlcywgZXNzYSBhYm9yZGFnZW0gw6kgdmnDoXZlbCBtYXMgc2VyaWEgbWFpcyBzaW1wbGVzIHVzYXIgdW0gRjEgcG9yIGV4ZW1wbG8pCgpBbGd1bnMgcHJlZGl0b3JlcyBzw6NvIG51bcOpcmljb3MgbWFzIGEgbWFpb3JpYSDDqSBjYXRlZ29yaWNhLCBhcyBjYXRlZ29yaWNhcyBmb3JhbSBiaW5hcml6YWRhcywgJDgwMCQgaW5zdMOibmNpYXMgc2Vyw6NvIHVzYWRhcyBwYXJhIHRyZWlubyBlICQyMDAkIHBhcmEgdGVzdGUuIE8gb2JqZXRpdm8gZGVzc2UgY2Fww610dWxvIMOpIGlsdXN0cmFyIGNvbW8gdHVuYXIgdW0gbW9kZWxvIHVzYW5kbyByZWFtb3N0cmFnZW0uCgoKIyMjRW5jb250cmFuZG8gb3MgcGFyw6JtZXRyb3MgZmluYWlzCkNvbW8gZXNjb2xoZXIgbyBtZWxob3IgbW9kZWxvPyBVbWEgaWTDqWlhIMOpIHBlZ2FyIG8gcXVlIHRpdmVyIG8gbWVsaG9yIHNjb3JlIGUgdXNhci4gVW0gbW9kZWxvIG7Do28gbGluZWFyIFNWTSBmb2kgZml0YWRvIHBhcmEgdmFsb3JlcyBkZSBjdXN0byBlbnRyZSAkMl57LTJ9JCBhdMOpICQyXns3fSQuIENhZGEgbW9kZWxvIGZvaSB0ZXN0YWRvIGNvbSBjaW5jbyByZXBldGnDp8O1ZXMgZGUgMTAtZm9sZCBjcm9zcy12YWxpZGF0aW9uIGFzIGZpZ3VyYXMgYWJhaXhvIG1vc3RyYW0gb3MgdmFsb3JlcyBkZSBhY3Vyw6FjaWEgcGFyYSAKCiFbYWN1csOhY2lhIHggdmFsb3IgZG8gY3VzdG9dKC4vQ2gwNEZpZzA5LnBuZykKCgohW2FjdXLDoWNpYSB4IHZhbG9yIGRvIGN1c3RvXSguL3RhYmVsaW5oYS5qcGVnKQoKUGFyYSBjYWRhIG1vZGVsbyBmb3JhbSBnZXJhZG9zIDUwIGVzdGltYXRpdmFzIGRhIGFjdXLDoWNpYW9zIHBvbnRvcyB2ZXJtZWxob3MgZG8gZ3LDoWZpY29zIHPDo28gYXMgbcOpZGlhcyBkZXNzYXMgZXN0aW1hdGl2YXMgYXMgYmFycmFzIHPDo28gMiAkXHBtJCBkZXN2aW9zIHBhZHLDo28gZGEgbcOpZGlhIGRvIGVycm8uIE8gcHJvZmlsZSBkZSB0cmVpbmFtZW50byBtb3N0cmEgdW0gaW5jcmVtZW50byBuYSBhY3Vyw6FjaWEgYXTDqSBvIHZhbG9yIGRlIGN1c3RvIDggZGVwb2lzIGRpc3NvIHRlbW9zIHVtIGRlY3LDqXNjaW1vIGNvbnTDrW51byBpbmRpY2FuZG8gdW0gb3ZlcmZpdHRpbmcuIFBlcmNlYmEgcXVlIHBlbGEgYWN1csOhY2lhIGFwYXJlbnRlIG8gbW9kZWxvIG1lbGhvcmEgYSBtZWRpZGFkIHF1ZSBvIGN1c3RvIGF1bWVudGEgYXTDqSA4LCBkZXBvaXMgb2NvcnJlIHVtIG92ZXJmaXR0aW5nLgoKRXNjb2xoZXIgbyBwb250byBkZSDDs3RpbW8gcGFyYSBvIG1vZGVsbyBwb2RlIG7Do28gc2VyIHVtIGJvYSBpZMOpaWEgZGFkbyBxdWUgc8OjbyBwcmVmZXLDrXZlaXMgbW9kZWxvcyBtYWlzIHNpbXBsZXMgZG8gcXVlIG9zIGNvbXBsZXhvcy4gVW1hIGFib3JkYWdlbSBkaWZlcmVudGUgw6kgKipvbmUtc3RhbmRhcmQgZXJyb3IqKiBxdWUgZW5jb250cmEgbyB2YWxvciBkZSDDs3RpbW8gZSBhbyBtZXNtbyB0ZW1wbyBzZXUgZXJybyBwYWRyw6NvLCBlbSBzZWd1aWRhIHByb2N1cmEgbyBtb2RlbG8gbWFpcyBzaW1wbGVzIGNvbSBkaXN0w6JuY2lhIGRlIHVtIGVycm8gcGFkcsOjbyBkbyBtZWxob3IgdmFsb3IgbnVtw6lyaWNvLiBOYSBmaWd1cmEgYWJhaXhvIHBvZGVtb3MgdmVyIHF1ZSBvIHZhbG9yIGRlIGFjdXLDoWNpYSBwYXJhIGN1c3RvIDggw6kgJDAuN1wlJAplc3NhIHTDqWNuaWNhIGVuY29udHJhcsOhIG8gbWVsaG9yIG1vZGVsbyBjb20gYWN1csOhY2lhIG7Do28gbWVub3MgcXVlICQ3NC4zJSQgKCQ3NVwlIC0gMC43XCUkKSBlc2NvbGhlbmRvIG8gdmFsb3IgZGUgY3VzdG8gJDIkLgoKT3V0cmEgYWJvcmRhZ2VtIMOpIGVzY29saGVyIHVtIG1vZGVsbyBtYWlzIHNpbXBsZXMgZGVudHJvIGRlIHVtYSBjZXJ0YSB0b2xlcsOibmNpYSBkbyB2YWxvciBudW3DqXJpY28gw7N0aW1vLiBPIHBlcmNlbnR1YWwgZGUgZGVzY3LDqXNjaW1vIGRhIHBlcmZvcm1hbmNlIHBvZGUgc2VyIGNhbGN1bGFkbyBwb3IgJChYLU8pL08kIG9uZGUgJFgkIMOpIGEgcGVyZm9ybWFuY2UgZSAkTyQgw6kgbyB2YWxvciBudW3DqXJpY28gw7N0aW1vLiBQb3IgZXhlbXBsbywgbmEgZmlndXJhIGNvbSBvIGN1c3RvIGRvIFNWTSBhIG1lbGhvciBhY3Vyw6FjaWEgZGUgYWNvcmRvIGNvbSBvIHByb2ZpbGUgZm9pICQ3NVwlJCBzZSB1bWEgcGVyZGEgZGUgNCBuYSBhY3Vyw6FjaWEgZm9yIGFjZWl0w6F2ZWwsIGNvbW8gdHJhZGUgb2ZmIHBhcmEgdW0gbW9kZWxvIG1haXMgc2ltcGxlcywgdmFsb3JlcyBkZSBhY3Vyw6FjaWEgbWFpb3JlcyBxdWUgJDcxLjJcJSQgcG9kZXJpYW0gc2VyIGFjZWl0b3MsIHVtIHZhbG9yIGRlIGN1c3RvICQxJCBwb2RlcmlhIHNlciBhY2VpdG8gbmVzc2UgbW9kZWxvLgoKTmEgZmlndXJhIGFiYWl4byBmb3JhbSB0ZXN0YWRvcyBkaXZlcnNvcyBtw6l0b2RvcyBkZSByZWFtb3N0cmFnZW0gZW50cmUgZWxlczogMTAtZm9sZCBjcm9zcy12YWxpZGF0aW9uLCBMT09DViwgcmVwZWF0ZWQgY3Jvc3MtdmFsaWRhdGlvbiwgYm9vdHN0cmFwIChjb20gZSBzZW0gYWp1c3RlICQ2MzIkKSBlIHJlcGVhdGVkIHRyYWluaW5nL3Rlc3Qgc3BsaXQgKCQyMFwlJCBkZSBoZWxkLW91dCkuIE9zIMO6bHRpbW9zIGRvaXMgdXNhbmRvIHJlYW1vc3RyYWdlbSBkZSA1MCBwYXJhIGVzdGltYXIgYSBwZXJmb3JtYW5jZS4KCiFbQm9vdHN0cmFwXSguL0NoMDRGaWcxMC5wbmcpCgpUb2RhcyBhcyB2YWxpZGHDp8O1ZXMgY3J1emFkYXMgYXByZXNlbnRhbSB1bSBwYWRyw6NvIGRlIHBvbnRvIMOzdGltbyBlbnRyZSAkNCQgZSAkMTYkIHNlZ3VpZG9zIGRlIHVtYSBxdWVkYSBkZSBkZXNlbXBlbmhvLCBtdWl0byBwcm92w6F2ZWwgb3ZlcmZpdHRpbmcuIENvbSBleGNlc3PDo28gZG8gYm9vdHN0cmFwICQ2MzIkIHRvZGFzIGFzIHTDqWNuaWNhcyB0ZW0gdW0gcGljbywgcXVlIMOpIGF0aW5naWRvIHJhcGlkYW1lbnRlLCBzZWd1aWRvIHBlbGEgcXVlZGEgZG8gb3ZlcmZpdHRpbmcuIEFzIHTDqWNuaWNhcyBkZSBjcm9zcy12YWxpZGF0aW9uIHRlbSBhY3Vyw6FjaWEgZW50cmUgJDc0LjVcJSQgJDc2LjZcJSQuIE8gYm9vdHN0cmFwIHNpbXBsZXMgdGVtIG8gcGlvciBkZXNlbXBlbmhvICQ3NC4yXCUkIGUgbyBib290c3RyYXAgJDYzMiQgc3VwZXIgY29tcGVuc2EgbyBiaWFzIGUgZXN0aW1hIGNvbSAkODIuM1wlJCBkZSBhY3Vyw6FjaWEuCgpBIGxhcmd1cmEgZG8gZXJybyBwYWRyw6NvIGRvIDEwLWZvbGQgY3Jvc3MtdmFsaWRhdGlvbiDDqSBhIG1haW9yIGRlIHRvZGFzIHBvaXMgbyBlcnJvIHBhZHLDo28gw6kgdW1hIGZ1bsOnw6NvIGRvIG7Dum1lcm8gZGUgcmVhbW9zdHJhZ2VucyB1c2FkYXMgKDEwIHZlcnN1cyBhcyA1MCB1c2FkYXMgcGVsbyBib290c3RyYXApLiBBIHZlbG9jaWRhZGUgZGUgY29tcHV0YcOnw6NvIG8gbcOpdG9kbyBtYWlzIHLDoXBpZG8gw6k6IDEwLWZvbGQgY3Jvc3MgdmFsaWRhdGlvbiwgZW0gc2VndWlkYSB0ZW1vcywgcXVhc2UgZW1wYXRhZG9zLCByZXBlYXRlZCBjcm9zcyB2YWxpZGF0aW9uLCBib290c3RyYXAgZSByZXBlYXRlZCB0cmFpbmluZy90ZXN0IGUgTE9PQ1Ygw6kgbyBtYWlzIGRlbW9yYWRvLgoKCiMjI0RhdGEgU3BsaXQgcmVjb21lbmRhw6fDtWVzClBvbnRvcyBuZWdhdGl2b3MgZW0gdXNhciB1bSBjb25qdW50byBkZSB0ZXN0ZSDDum5pY28gZSBpbmRlcGVuZGVudGU6CgoxIC0gw4kgdW1hIHZhbGlkYcOnw6NvIMO6bmljYSBlIG7Do28gYXZhbGlhIGluY2VydGV6YXMgbm9zIHJlc3VsdGFkb3MKMiAtIFByb3BvcmNpb25hbG1lbnRlIGNvbmp1bnRvcyBkZSBkYWRvcyBncmFuZGVzIGF1bWVudGFtIG8gYmlhcyBkYSBlc3RpbWF0aXZhIGRlIHBlcmZvcm1hbmNlCjMgLSBDb20gY29uanVudG9zIGRlIGRhZG9zIHBlcXVlbm9zOgogICAgM2EgLSBPIG1vZGVsbyBuZWNlc3NpdGFyw6EgZGUgdG9kb3Mgb3MgcG9udG9zIHBhcmEgZXN0aW1hciBjb3JyZXRhbWVudGUKICAgIDNiIC0gQSBpbmNlcnRlemEgZG8gY29uanVudG8gZGUgdGVzdGUgcG9kZSBzZXIgY29uaXNkZXJhdmVsbWVudGUgbWFpb3IgZGFkbyBxdWUgY29uanVudG9zIGRlIHRlc3RlIGRpc3RpbnRvcyBwcm9kdXplbSByZXN1bHRhZG9zIGRpZmVyZW50ZXMKNCAtIG1ldG9kb3MgZGUgcmVhbW9zdHJhZ2VtIHByb2R1emVtIHJlc3VsdGFkb3MgYWNlaXTDoXZlaXMgZGUgY29tbyBvIG1vZGVsbyB2YWkgcGVyZm9ybWFyIG5vIGZ1dHVybwoKTsOjbyBleGlzdGUgdW0gbcOpdG9kbyBtZWxob3IgcXVlIG91dHJvLCBow6EgZGl2ZXJzYXMgc2l0dWHDp8O1ZXMgb25kZSBkZXZlbSBzZXIgYXZhbGlhZG9zIG9zIHRyYWRlLW9mZnMuIFBhcmEgY29uanVudG9zIGRlIGRhZG9zIHBlcXVlbm9zIMOpIG1lbGhvciB1bSAxMC1mb2xkIGNyb3NzLXZhbGlkYXRpb24gcG9pcyBvIGJpYXMgZSB2YXJpw6JuY2lhIHNlcsOjbyBvayBlIG8gY3VzdG8gY29tcHV0YWNpb25hbCwgZGFkbyBvIHRhbWFuaG8gZGEgYW1vc3RyYSwgbsOjbyBzZXLDoSBlbGV2YWRvLiBTZSBvIG9iamV0aXZvIMOpIGVzY29saGVyIGVudHJlIG1vZGVsb3MgZW0gb3Bvc2nDp8OjbyBhIGVzY29saGVyIG8gbWVsaG9yIGluZGljYWRvciBkZSBwZXJmb3JtYW5jZSwgc2VyaWEgcmVjb21lbmTDoXZlbCBlc2NvbGhlciB1bWEgdMOpY25pY2EgZGUgYm9vdHN0cmFwIHBvaXMgc3VhIHZhcmnDom5jaWEgw6kgYmFpeGEuIFBhcmEgY29uanVudG9zIGRlIGRhZG9zIGdyYW5kZXMgYSBkaWZlcmVuw6dhIGVudHJlIG3DqXRvZG9zIHNlIHRvcm5hIGlycmVsZXZhbnRlIGUgZXNjb2xoZW1vcyBlbnRyZSBwb2RlciBjb21wdXRhY2lvbmFsIHRpcG8gdW0gMTAtZm9sZCBjcm9zcy12YWxpZGF0aW9uIChkaXNjb3JkbyBkbyBhdXRvciwgZGV2ZW1vcyB1c2FyIHVtIG3DqXRvZG8gcGFyYSBvYnRlciBvIG1lbGhvciBtb2RlbG8gbWVzbW8gcXVlIGRlbW9yZSBhIGV4ZWN1w6fDo28pLgoKCiMjI0VzY29saGVuZG8gZW50cmUgbW9kZWxvcwpEZXBvaXMgZGUgZXNjb2xoZXIgb3MgcGFyw6JtZXRyb3Mgw7N0aW1vcyBwYXJhIGNhZGEgbW9kZWxvLCBkZXZlbW9zIGVzY29saGVyIHF1YWwgbyBtZWxob3IgbW9kZWxvIGVudHJlIHRvZG9zLiBFc3NhIHRhcmVmYSDDqSBiZW0gY29tcGxleGEsIHBhcmEgdGFsLCBkZXZlbW9zIHNlZ3VpciBvIHNlZ3VpbnRlIHByb2NlZGltZW50bzoKCjEgLSBDb21lw6dhciBjb20gbW9kZWxvcyBjb21wbGV4b3MgY29tbyBTVk0sIEJvb3N0ZWQgdHJlZSBxdWUgcHJvZHV6ZW0gcmVzdWx0YWRvcyDDs3RpbW9zCjIgLSBVc2FyIG1vZGVsb3MgbWFpcyBzaW1wbGVzIGUgcXVhc2UgaW50ZXJwcmV0w6F2ZWlzIE1BUlMsIHBhcnRpYWwgbGVhc3Qgc3F1YXJlcywgZ2VuZXJhbGl6ZWQgYWRpdGl2ZSBtb2RlbHMsIG5haXZlIGJheWVzCjMgLSBDb25zaWRlcmUgdXNhciBvIG1vZGVsbyBtYWlzIHNpbXBsZXMgcG9zc8OtdmVsIGRlbnRybyBkYSBwZXJmb3JtYW5jZSBlc3BlcmFkYSAow6kgdW0gdHJhZGUtb2ZmKS4KCkRlc3NhIGZvcm1hLCBwb2RlbW9zIGFjaGFyIG8gdGV0byBkZSBwZXJmb3JtYW5jZSBlIGRlcG9pcyBwb25kZXJhciBhdMOpIG9uZGUgcG9kZW1vcyBwZXJkZXIgZGUgcHJlY2lzw6NvIHBhcmEgZ2FuaGFyIGVtIGludGVycHJldGFiaWxpZGFkZS4gTm8gZ2VyYWwgYSBtYWlvcmlhIGRvcyBtb2RlbG9zIHRlbSByZXN1bHRhZG9zIHByw7N4aW1vcyBlbnTDo28gcG9kZW1vcyBlc2NvbGhlciBkZSBhY29yZG8gY29tIG9zIGJlbmVmw61jaW9zIGRhcyBkaWZlcmVudGVzIG1ldG9kb2xvZ2lhcy4gQ29tcGxleGlkYWRlLCBpbnRlcnByZXRhYmlsaWRhZGUsIGZhY2lsaWRhZGUgZW0gcHJlZGl6ZXIuIFVtIFNWTSBlIHJhbmRvbSBmb3Jlc3QgdGVtIGFjdXLDoWNpYSBleGNlbGVudGUgcG9yw6ltIHN1YXMgY29tcGxleGlkYWRlcyBjb21wdXRhY2lvbmFpcyBwb2RlbSBpbXBlZGlyIGRlIGNvbG9jYXJtb3MgZWxlcyBlbSBwcm9kdcOnw6NvLCBzZSB1bSBNQVJTIHRpdmVyIGRlc2VtcGVuaG8gbGV2ZW1lbnRlIGluZmVyaW9yIHBvZGVtb3MgdXNhciBlbGUgcG9pcyB0ZW0gdW0gdGVtcG8gZGUgZXhlY3XDp8OjbyBtdWl0byBpbmZlcmlvci4KCkNvbnNpZGVyYW5kbyBvIGV4ZW1wbG9kZSBzY29yYWdlbSBkZSBjcsOpZGl0byBvbmRlIHVzYW1vcyB1bSBTVk0gY29tIHJlcGVhdGVkIDEwLWZvbGQgY3Jvc3MtdmFsaWRhdGlvbiBhIGFjdXLDoWNpYSBlc3RpbWFkYSBkbyBtb2RlbG8gZXJhIGRlICQ3NVwlJCBjb20gYSBtYWlvcmlhIGRvcyByZXN1bHRhZG9zIGRlIHJlYW1vc3RyYWdlbSBlbnRyZSAkNjZcJSQgZSAkODJcJSQuIFVzYW5kbyB1bWEgbG9naXN0aWNhIGNvbSBvIG1lc21vIHNjaGVtYSBkZSBjcm9zcy12YWxpZGF0aW9uIG9idGl2ZW1vcyAkNzQuOVwlJCBjb20gYSBtYWlvcmlhIGRvcyByZXN1bHRhZG9zIGRlIHJlYW1vc3RyYWdlbSBlbnRyZSAkNjZcJSQgZSAkODJcJSQuIEFzIG1lc21hcyAkNTAkIHJlYW1vc3RyYWdlbnMgZm9yYW0gdXNhZGFzIHBhcmEgYXZhbGlhciBjYWRhIG1vZGVsbywgYSBmaWd1cmEgYWJhaXhvIG1vc3RyYSBhIGRpc3RyaWJ1acOnw6NvIGRlIGFtYm9zCgohW0Jvb3RzdHJhcF0oLi9DaDA0RmlnMTEucG5nKQoKRGFkbyBxdWUgYSBhY3Vyw6FjaWEgZm9pIG1ldHJpZmljYWRhIHVzYW5kbyBvIG1lc21vIGNvbmp1bnRvIGRlIGRhZG9zIHJlYW1vc3RyYWRvIGRhIG1lc21hIGZvcm1hLCBlc3RhdMOtc3RpY2FzIHBhcmEgY29tcGFyYXPDo28gZW0gcGFyZXMgcG9kZW0gc2VyIHVzYWRhcyBwYXJhIGRldGVybWluYXIgc2UgYXMgZGlmZXJlbsOnYXMgZW50cmUgbW9kZWxvcyDDqSBlc3RhdGlzdGljYW1lbnRlIHNpZ25pZmljYW50ZS4gVW0gdC10ZXN0IHBhcmVhZG8gcG9kZSBzZXIgdXNhZG8gcGFyYSBjb21wYXJhciBzZSBhIGFjdXLDoWNpYSAobcOpZGlhKSBkb3MgbW9kZWxvcywgb3UgYSBkaWZlcmVuw6dhIG3DqWRpYSBuYSBhY3Vyw6FjaWEgZG9zIGRhdGEgc2V0cyByZWFtb3N0cmFkb3Mgw6kgemVyby4gUGFyYSBhbWJvcyBvcyBtb2RlbG9zIGEgZGlmZXJlbsOnYSBtw6lkaWEgbmEgYWN1csOhY2lhIGRvcyBtb2RlbG9zIGZvaSBkZSAkMC4xXCUkIGNvbSBhIGxvZ2lzdGljYSB0ZW5kbyByZXN1bHRhZG9zIG1lbGhvcmVzLiBPIGludGVydmFsbyBkZSBjb25maWFuw6dhIGRlICQ5NVwlJCBmb2kgZGUgKCQtMS4yXCUkLCAkMVwlJCkgaW5kaWNhbmRvIHF1ZSBhIGFjdXLDoWNpYSBkZSBuZW5odW0gZG9zIG1vZGVsb3Mgw6kgc2lnbmlmaWNhbnRlbWVudGUgbWVsaG9yLiAKClF1YW5kbyBzw6NvIHVzYWRhcyB2w6FyaWFzIG1ldG9kb2xvZ2lhcyBwYXJhIGNvbXBhcmFyIG1vZGVsb3MgcG9kZW1vcyBjaGVnYXIgZW0gc2l0dWHDp8O1ZXMgY29uZmxpdGFudGVzLCBkZXBlbmRlbmRvIGRvIHByb2JsZW1hIGEgc2VyIHRyYXRhZG8gZGV2ZW1vcyBjb25zaWRlcmFyIG8gcGVzbyBkZSB1bWEgZXN0YXTDrXN0aWNhIG1haW9yIHF1ZSBkZSBvdXRyby4gRXNwZWNpZmljaWRhZGUgZSBzZW5zaXRpdmlkYWRlIHBvZGVtIHNlciB1c2Fkb3MgcGFyYSBjb21wYXJhciAgbW9kZWxvcy4gU2UgbyBjb25qdW50byBkZSBkYWRvcyB0ZW0gbWFpcyAqZXZlbnRvcyogcXVlICpuw6NvIGV2ZW50b3MqIHNlbnNpdGl2aWRhZGUgcG9kZSBzZXIgdXNhZG8gbWVsaG9yIHF1ZSBlc3BlY2lmaWNpZGFkZS4gQ29tIGF1bWVudG8gZGUgcHJlY2lzw6NvIGjDoSB1bWEgdmVyaXNzaW1pbGhhbsOnYSBtYWlvciBxdWUgbW9kZWxvcyBwb2RlbSBzZXIgZGlmZXJlbmNpYWRvcyBlbSB0ZXJtb3MgZGUgc2Vuc2l0aXZpZGFkZSBkbyBxdWUgZXNwZWNpZmljaWRhZGUuCgojIyNDb21wdXRhw6fDo28gOikKCgoKCgoKCg==